'''
Created on Feb 17, 2013

@author: Petko
'''
import uuid
from sqlalchemy.orm.session import Session
from sent.model import BaseDBManager
from sent.model.entities.user import User, Permission, Group, GroupPermission,\
    UserGroup, GroupBaseOpinionPermissions, GroupViewPermissions
from sententialyzer.settings import DbSession, SENTENTIALYZER_ADMIN_USER_NAME,\
    SENTENTIALYZER_ADMIN_GROUP_NAME, SENTENTIALYZER_DEFAULT_GROUP_NAME,\
    SENTENTIALYZER_DEFAULT_USER_GROUP_PERMISSIONS, DbSessionRO
from sent.utils.sent_logger import sent_logger
from sent.utils.permissions import GROUP_PERMISSIONS, OPINION_PERMISSIONS, Scope,\
    VIEW_PERMISSIONS
from sent.model.entities.opinion import ViewEnt

logger = sent_logger( __name__ )

class PermissionManager:
    
    #the key is the permission name, the value is an instance of Permission entity
    permissionCache = {}
    
    #defaultGroup = 
    
    def __init__(self):
        dbSession = DbSession()
        assert isinstance(dbSession, Session)
        allPermissions = dbSession.query(Permission).all()
        
        for neededPermissionStr in GROUP_PERMISSIONS + OPINION_PERMISSIONS + VIEW_PERMISSIONS:
            
            isFound = False
            for permission in allPermissions:
                assert isinstance(permission, Permission)
                if permission.permission_name == neededPermissionStr:
                    isFound = True
                    self.permissionCache[neededPermissionStr] = permission
                    dbSession.expunge(permission)
                    break
                
            if not isFound:
                logger.log(sent_logger.INFO, 'Inserting permission %s', neededPermissionStr)
                permission = Permission()
                permission.permission_name = neededPermissionStr
                dbSession.add(permission)
                self.permissionCache[neededPermissionStr] = permission
                dbSession.commit()
                dbSession.refresh(permission)
                dbSession.expunge(permission)
                
        dbSession.close()
        
g_permissionManager = PermissionManager()
g_adminUser=None
g_defaultGroup=None

class UserDBManager(BaseDBManager):
    '''
    classdocs
    '''

    def __init__(self, isReadOnly):
        '''
        Constructor
        '''
        BaseDBManager.__init__(self)
        
        if isReadOnly:
            self.dbSession = DbSessionRO()
        else:
            self.dbSession = DbSession()
    
    def createUser(self, user):
        global g_defaultGroup
        assert isinstance(user, User)
        dbSession=self.dbSession
        assert isinstance(dbSession, Session)
        
        internal_id = self.generateUUID()
        user.setUUID(internal_id)
        dbSession.add(user)
        
        self.addUserToGroup(g_defaultGroup.id, user.id)
        
        pass
    
    def getUserByExtId(self, extId):
        dbSession=self.dbSession
        assert isinstance(dbSession, Session)
        
        return dbSession.query(User).filter_by(external_id=unicode(extId)).first()

    def createGroup(self, group):
        assert isinstance(group, Group)
        dbSession=self.dbSession
        assert isinstance(dbSession, Session)
        
        group.setUUID(self.generateUUID())
        dbSession.add(group)
    
    def getGroupByExtId(self, extId):
        dbSession=self.dbSession
        assert isinstance(dbSession, Session)
        
        return dbSession.query(Group).filter_by(external_id=unicode(extId)).first()
    
    def setGroupPermissions(self, groupId, permissions):
        dbSession=self.dbSession
        assert isinstance(dbSession, Session)
        
        for permission in permissions:
            permissionEnt=g_permissionManager.permissionCache[str(permission)]
            assert isinstance(permissionEnt, Permission)
            
            groupPermissionEnt=GroupPermission()
            groupPermissionEnt.id = groupId
            groupPermissionEnt.permission_id = permissionEnt.permission_id
            dbSession.merge(groupPermissionEnt)
    
    def getGroupPermissions(self, userId):
        dbSession=self.dbSession
        assert isinstance(dbSession, Session)
        
        dbResult = dbSession.execute("SELECT DISTINCT perm.permission_name FROM " 
            + " User_Groups as ug, UGroup as g, Group_Permissions as gp, Permission as perm"
            + " WHERE ug.group_id=g.id"
            + " AND gp.id=g.id"
            + " AND gp.permission_id=perm.permission_id"
            + " AND ug.user_id=:user_id", {'user_id': userId})
        allRows = dbResult.fetchall()
        
        result = set()
        for row in allRows:
            #assert isinstance(row, RowProxy)
            scopeStr=row[0]
            result.add(str(scopeStr))
            #logger.log(DEBUG, scopeStr)
            
        return result
    
    def getOpinionsPermissions(self, userId, opIdsList):
        
        q = self.dbSession.query(GroupBaseOpinionPermissions.opinion_id). \
            join(Permission, GroupBaseOpinionPermissions.permission_id == Permission.permission_id ). \
            join(UserGroup, UserGroup.group_id == GroupBaseOpinionPermissions.group_id). \
            filter(UserGroup.user_id == userId, \
                   GroupBaseOpinionPermissions.opinion_id.in_(opIdsList))
            
        q = q.add_columns(Permission.permission_name)
        
        allRows = q.all()
        
        resultDict = {}
        
        for row in allRows:
            op_id = row[0]
            permissionName = row[1]
            
            opIdStr = str(uuid.UUID(bytes=op_id))
            
            scope = resultDict.get(opIdStr, None)
            if scope:
                scope.opinionPermissions.add(permissionName)
            else:
                scope = Scope(opIdStr + ':' + permissionName)
                resultDict[opIdStr] = scope
            
        return resultDict
    
    def getViewPermissions(self, userId, viewIdsList):
        q = self.dbSession.query(ViewEnt.external_id). \
            join(GroupViewPermissions, GroupViewPermissions.view_id == ViewEnt.id). \
            join(Permission, GroupViewPermissions.permission_id == Permission.permission_id ). \
            join(UserGroup, UserGroup.group_id == GroupViewPermissions.group_id). \
            filter(UserGroup.user_id == userId, \
                   ViewEnt.external_id.in_(viewIdsList))
            
        q = q.add_columns(Permission.permission_name)
        
        allRows = q.all()
        
        resultDict = {}
        
        for row in allRows:
            view_id = row[0]
            permissionName = row[1]
            
            scope = resultDict.get(view_id, None)
            if scope:
                scope.viewPermissions.add(permissionName)
            else:
                scope = Scope(view_id + ':' + permissionName)
                resultDict[view_id] = scope
                
        return resultDict
    
    def addUserToGroup(self, groupId, userId):
        dbSession=self.dbSession
        assert isinstance(dbSession, Session)
        
        userGroup = UserGroup()
        userGroup.group_id = groupId
        userGroup.user_id = userId
        dbSession.merge(userGroup)
        
    def removeUserFromGroup(self, userExtId, groupExtId):
        dbSession=self.dbSession
        assert isinstance(dbSession, Session)
        
        userSl = dbSession.query(User.id).filter(User.external_id == userExtId).subquery()
        groupSl = dbSession.query(Group.id).filter(Group.external_id == groupExtId).subquery()
        return dbSession.query(UserGroup).filter(UserGroup.user_id.in_(userSl), 
                                                 UserGroup.group_id.in_(groupSl)).delete(synchronize_session=False)
        
    def getGroupUsers(self, groupExtId, offset, size):
        groupSl = self.dbSession.query(Group.id).filter(Group.external_id == groupExtId).subquery()
        q = self.dbSession.query(User).join(UserGroup, User.id == UserGroup.user_id).filter(UserGroup.group_id.in_(groupSl))
        return self.paginateResults(q, offset, size)
    
    def getUserGroups(self, userId, offset, size):
        userSl = self.dbSession.query(User.id).filter(User.external_id == userId).subquery()
        q = self.dbSession.query(Group).join(UserGroup, Group.id == UserGroup.group_id).filter(UserGroup.user_id.in_(userSl))
        return self.paginateResults(q, offset, size)
    
def initUserDB():
    global g_adminUser
    global g_defaultGroup
    
    dbMan = UserDBManager(False)
    
    defaultGroup = dbMan.getGroupByExtId(SENTENTIALYZER_DEFAULT_GROUP_NAME)
    if not defaultGroup:
        defaultGroup = Group()
        defaultGroup.external_id = SENTENTIALYZER_DEFAULT_GROUP_NAME
        dbMan.createGroup(defaultGroup)
        dbMan.setGroupPermissions(defaultGroup.id, SENTENTIALYZER_DEFAULT_USER_GROUP_PERMISSIONS)
    
    g_defaultGroup = defaultGroup
    dbMan.expunge(g_defaultGroup)
    
    admin = dbMan.getUserByExtId(SENTENTIALYZER_ADMIN_USER_NAME)
    if not admin:
        admin = User()
        admin.external_id=SENTENTIALYZER_ADMIN_USER_NAME
        admin.rating=0
        dbMan.createUser(admin)
    
    g_adminUser = admin
    dbMan.expunge(g_adminUser)
    
    adminGroup = dbMan.getGroupByExtId(SENTENTIALYZER_ADMIN_GROUP_NAME)
    
    if not adminGroup:
        adminGroup = Group()
        adminGroup.external_id = SENTENTIALYZER_ADMIN_GROUP_NAME
        dbMan.createGroup(adminGroup)
        dbMan.setGroupPermissions(adminGroup.id, GROUP_PERMISSIONS)
        
    dbMan.addUserToGroup(adminGroup.id, admin.id)
    
    dbMan.commitSession()
    
    dbMan.closeSession()
    
initUserDB()
#='sent_default_group'